package demo.command.domain.user;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import demo.command.base.ComplexHandler;
import demo.command.base.Event;
import demo.command.base.EventBus;
import demo.command.base.EventFactory;
import demo.command.domain.blog.BlogLikedEvent;
import demo.command.domain.blog.BlogStateUpdatedEvent;
import demo.command.domain.feed.Feed;
import demo.command.domain.feed.ViewFeed;
import demo.command.domain.tag.Tag;
import demo.command.domain.tag.TagStateUpdatedEvent;
import demo.command.domain.topic.TopicStateUpdatedEvent;
import demo.infrastructure.DateUtil;
import demo.infrastructure.LogUtil;

//
//
//  Generated by StarUML(tm) Java Add-In
//
//  @ Project : Uservent&oo
//  @ File Name : User.java
//  @ Date : 2013/9/27
//  @ Author : bner
//
//

public class User extends ComplexHandler<Event> implements Cloneable {

	private String id;

	private int credits;

	private List<String> tags = new ArrayList<String>();

	private Collection<String> followers = new ArrayList<String>();
	private Collection<String> topics = new ArrayList<String>();

	private transient List<Feed> feedList = new ArrayList<Feed>();
	private transient List<UserViewFeed> viewFeedList = new ArrayList<UserViewFeed>();
	private transient List<String> notificationList = new ArrayList<String>();

	private transient UserRepository repo = new UserRepository();

	public User(String id) {
		this.id = id;

		EventBus.registHandler(BlogStateUpdatedEvent.class, this);
		EventBus.registHandler(UserProfileUpdatedEvent.class, this);
		EventBus.registHandler(TopicStateUpdatedEvent.class, this);
		EventBus.registHandler(UserTagAddedEvent.class, this);
		EventBus.registHandler(TagStateUpdatedEvent.class, this);
	}

	public void follow(User user) {
		this.followers.add(user.id);
	}

	public void subscribe(String topicId) {
		this.topics.add(topicId);
	}

	public void addTags(List<Tag> tagObjs) {

		List<String> tags = new ArrayList<String>();
		for (Tag tag : tagObjs) {
			if (!this.tags.contains(tag.getId())) {
				this.tags.add(tag.getId());
				tags.add(tag.getId());
				tag.addRefObject(id, "User");
			}
		}
		UserTagAddedEvent event = EventFactory.createEvent(
				UserTagAddedEvent.class, this);
		event.setUserId(id);
		event.setTags(tags);

		EventBus.send(event);
	}

	public String getId() {
		return this.id;
	}

	public List<String> getTags() {
		return tags;
	}

	public int getCredits() {
		return credits;
	}

	public void setCredits(int credits) {
		this.credits = credits;
	}

	public Collection<String> getFollowers() {
		return followers;
	}

	public void setFollowers(Collection<String> followers) {
		this.followers = followers;
	}

	public Collection<String> getTopics() {
		return topics;
	}

	public void setTopics(Collection<String> topics) {
		this.topics = topics;
	}

	public void setTags(List<String> tags) {
		this.tags = tags;
	}

	public UserVO getUserVO() {
		UserVO userVO = new UserVO();

		userVO.setId(id);
		userVO.setCredits(credits);
		userVO.setTags(tags);

		return userVO;
	}

	private UserRepoVO getUserRepoVO() {
		UserRepoVO userVO = new UserRepoVO();

		userVO.setId(id);
		userVO.setCredits(credits);
		userVO.setTags(tags);

		userVO.setFollowers(followers);
		userVO.setTopics(topics);
		userVO.setLastSaveDate(DateUtil.getSysDate());

		return userVO;
	}

	@Override
	protected void doHandle(Event event) {
		if (event instanceof BlogStateUpdatedEvent) {
			BlogStateUpdatedEvent blogStateUpdatedEvent = (BlogStateUpdatedEvent) event;
			if (blogStateUpdatedEvent.getOperId().equals(this.id)) {
				String message = this.id + " "
						+ blogStateUpdatedEvent.getOperation() + " "
						+ blogStateUpdatedEvent.getBlogId();
				Feed feed = new Feed(event, this.getUserVO(), message,
						blogStateUpdatedEvent.getBlogId(),
						Feed.ResourceType_Blog);
				this.feedList.add(feed);

				LogUtil.print("User(" + this.id + ") Feed " + feed.getId()
						+ " Created, Operation="
						+ blogStateUpdatedEvent.getOperation());
			}
			if (blogStateUpdatedEvent.getOwnerId().equals(this.id)) {
				this.credits++;

				LogUtil.print("User(" + this.id + ") credits ++ ,credits="
						+ this.credits);

				UserProfileUpdatedEvent updateEvent = EventFactory.createEvent(
						UserProfileUpdatedEvent.class, event, this);
				updateEvent.setUserId(this.id);
				updateEvent.setTags(tags);
				EventBus.send(updateEvent);
			}

		} else if (event instanceof UserProfileUpdatedEvent) {
			UserProfileUpdatedEvent userProfileUpdatedEvent = (UserProfileUpdatedEvent) event;
			if (userProfileUpdatedEvent.isSelf(this.id)) {
				BlogLikedEvent blogLikedEvent = userProfileUpdatedEvent
						.getTheSource(BlogLikedEvent.class);
				if (blogLikedEvent != null) {
					String notification = blogLikedEvent.getOperId() + " like "
							+ " your " + blogLikedEvent.getBlogId() + " Blog.";
					this.notificationList.add(notification);

					LogUtil.print("User " + this.id
							+ " receive Notification : " + notification);
				}
			}

			else if (userProfileUpdatedEvent.isOperator()) {
				UserViewFeed viewFeed = new UserViewFeed(event,
						userProfileUpdatedEvent.getFeed(), this.id,
						userProfileUpdatedEvent.getUserId());
				this.viewFeedList.add(viewFeed);

				LogUtil.print("User " + this.id + " receive Feed From User "
						+ userProfileUpdatedEvent.getUserId() + " FeedId="
						+ userProfileUpdatedEvent.getFeed());
			}
		} else if (event instanceof TopicStateUpdatedEvent) {
			TopicStateUpdatedEvent topicStateUpdatedEvent = (TopicStateUpdatedEvent) event;
			UserViewFeed viewFeed = new UserViewFeed(event,
					((UserProfileUpdatedEvent) topicStateUpdatedEvent
							.getSource()).getFeed(), this.id,
					topicStateUpdatedEvent.getOperatorId());
			this.viewFeedList.add(viewFeed);

			LogUtil.print("User "
					+ this.id
					+ " receive Feed From Topic "
					+ topicStateUpdatedEvent.getTopicId()
					+ " FeedId="
					+ ((UserProfileUpdatedEvent) topicStateUpdatedEvent
							.getSource()).getFeed());
		} else if (event instanceof UserTagAddedEvent) {
			UserTagAddedEvent userTagAddedEvent = (UserTagAddedEvent) event;

			LogUtil.print("User " + this.id + " add Tags, Tags="
					+ userTagAddedEvent.getTagInfos());

			String message = this.id + " add Tags, Tags="
					+ userTagAddedEvent.getTagInfos();

			Feed feed = new Feed(event, this.getUserVO(), message, this.id,
					Feed.ResourceType_User);
			this.feedList.add(feed);

			LogUtil.print("User(" + this.id + ") Feed " + feed.getId()
					+ " Created, Operation="
					+ UserTagAddedEvent.class.getName());

			this.credits++;

			LogUtil.print("User " + this.id + " credits ++ ,credits="
					+ this.credits);
		} else if (event instanceof TagStateUpdatedEvent) {
			TagStateUpdatedEvent tagStateUpdatedEvent = (TagStateUpdatedEvent) event;

			String notification = "Tag " + tagStateUpdatedEvent.getContent()
					+ " heat++ heat=" + tagStateUpdatedEvent.getHeat();
			this.notificationList.add(notification);

			LogUtil.print("User " + this.id + " receive Notification : "
					+ notification);

		}

	}

	@Override
	protected boolean isInterestedEvent(Event event) {
		if (event instanceof BlogStateUpdatedEvent) {
			BlogStateUpdatedEvent blogStateUpdatedEvent = (BlogStateUpdatedEvent) event;
			if (blogStateUpdatedEvent.getOwnerId().equals(this.id)
					|| blogStateUpdatedEvent.getOperId().equals(this.id)) {
				return true;
			}
		}
		if (event instanceof UserProfileUpdatedEvent) {
			UserProfileUpdatedEvent userProfileUpdatedEvent = (UserProfileUpdatedEvent) event;
			if (this.followers.contains(userProfileUpdatedEvent.getUserId())) {
				return true;
			}
			if (userProfileUpdatedEvent.isSelf(this.id)
					&& userProfileUpdatedEvent.isOwner()) {
				return true;
			}
		}
		if (event instanceof TopicStateUpdatedEvent) {
			TopicStateUpdatedEvent topicStateUpdatedEvent = (TopicStateUpdatedEvent) event;
			if (this.topics.contains(topicStateUpdatedEvent.getTopicId())) {
				if (topicStateUpdatedEvent.getOperatorId() != null
						&& !topicStateUpdatedEvent.getOperatorId().equals(
								this.id)) {
					return true;
				}
			}
		}
		if (event instanceof UserTagAddedEvent) {
			UserTagAddedEvent userTagAddedEvent = (UserTagAddedEvent) event;
			if (this.id.equals(userTagAddedEvent.getUserId())) {
				return true;
			}
		}
		if (event instanceof TagStateUpdatedEvent) {
			TagStateUpdatedEvent tagStateUpdatedEvent = (TagStateUpdatedEvent) event;
			if (tagStateUpdatedEvent.getOperator() != null
					&& !this.id.equals(tagStateUpdatedEvent.getOperator())
					&& this.tags.contains(tagStateUpdatedEvent.getContent())) {
				return true;
			}
		}

		return false;
	}

	@Override
	public void load() {
		UserRepoVO userVO = repo.find(this.id);

		this.setCredits(userVO.getCredits());
		this.setTags(userVO.getTags());
		this.setFollowers(userVO.getFollowers());
		this.setTopics(userVO.getTopics());
		this.setLastSaveDate(userVO.getLastSaveDate());

	}

	@Override
	public void save() throws Exception {
		repo.save(this.getUserRepoVO());
	}

	@Override
	public String toString() {
		StringBuilder info = new StringBuilder();
		info.append("\nUser : ");
		info.append(id);
		info.append("\n");

		info.append("Credits : ");
		info.append(credits);
		info.append("\n");

		info.append("Tags : ");
		for (String tag : tags) {
			info.append(tag);
			info.append(",");
		}
		info.append("\n");

		info.append("Followers : ");
		for (String follower : followers) {
			info.append(follower);
			info.append(",");
		}
		info.append("\n");

		info.append("subscribed Topics : ");
		for (String topic : topics) {
			info.append(topic);
			info.append(",");
		}
		info.append("\n");

		info.append("feedList : ");
		for (Feed feed : feedList) {
			info.append("\n");
			info.append(feed);
		}
		info.append("\n");

		info.append("viewFeedList : ");
		for (ViewFeed feedView : viewFeedList) {
			info.append("\n");
			info.append(feedView);
		}
		info.append("\n");

		info.append("notificationList : ");
		for (String notification : notificationList) {
			info.append("\n");
			info.append(notification);
		}
		info.append("\n");

		return info.toString();
	}

	@Override
	public User clone() throws CloneNotSupportedException {
		User newObj = new User(id);

		newObj.credits = this.credits;

		for (String tag : tags) {
			newObj.tags.add(tag);
		}

		for (String follower : followers) {
			newObj.followers.add(follower);
		}

		for (String topic : topics) {
			newObj.topics.add(topic);
		}

		for (Feed feed : feedList) {
			newObj.feedList.add((Feed) feed.clone());
		}

		for (UserViewFeed feedView : viewFeedList) {
			newObj.viewFeedList.add((UserViewFeed) feedView.clone());
		}

		for (String notification : notificationList) {
			newObj.notificationList.add(notification);
		}

		newObj.setLastSaveDate(this.getLastSaveDate());

		return newObj;
	}
}
